package com.thoughtworks.turtlemock.filemover;

import junit.framework.TestCase;
import org.easymock.MockControl;

import java.io.File;

public class FileMoverEasyMockTest extends TestCase {
    private static final String A_FILE_NAME = "aFileName.ext";
    private static final String A_FILE_PATH = "aFileDir" + File.separator + A_FILE_NAME;
    private static final String A_DIR = "aDir";
    private static final String ANOTHER_FILE_NAME = "anotherFileName.ext";
    private static final String ANOTHER_FILE_PATH = "anotherFileDir" + File.separator + ANOTHER_FILE_NAME;

    private static class FileMockController {
        private MockControl mockControl;
        private MockControl destFileMockControl;
        private FileAdaptee destFileMock;
        private final String filePath;
        private FileAdaptee mock;

        public FileMockController(String fileName, String destDir, String filePath) {
            this.filePath = filePath;
            setUpExpection(fileName, destDir);
        }

        private void setUpExpection(String fileName, String destDir) {
            mockControl = MockControl.createControl(FileAdaptee.class);
            destFileMockControl = MockControl.createControl(FileAdaptee.class);

            mock = (FileAdaptee) mockControl.getMock();
            destFileMock = (FileAdaptee) destFileMockControl.getMock();

            mock.getName();
            mockControl.setReturnValue(fileName);

            mock.moveTo(destDir + File.separator + fileName);
            mockControl.setReturnValue(destFileMock);
        }

        public FileAdaptee fileMock() {
            return mock;
        }

        public void verify() {
            mockControl.verify();
            destFileMockControl.verify();
        }

        public void replay() {
            mockControl.replay();
            destFileMockControl.replay();
        }

        public void setUpShouldBeRollbackableExpection() {
            destFileMock.moveTo(filePath);
            destFileMockControl.setReturnValue(mock);
            mock.getAbsolutePath();
            mockControl.setReturnValue(filePath);
        }
    }

    private FileMover aFileMover;
    private MockControl aDirMockControl;
    private FileMockController fileMockController;

    protected void setUp() throws Exception {
        aDirMockControl = MockControl.createControl(FileAdaptee.class);
        FileAdaptee aDirMock = (FileAdaptee) aDirMockControl.getMock();
        aDirMock.getAbsolutePath();
        aDirMockControl.setDefaultReturnValue(A_DIR);

        fileMockController = new FileMockController(A_FILE_NAME, A_DIR, A_FILE_PATH);

        aFileMover = new FileMover(aDirMock);
    }

    public void testShoudMoveFileToTargetDir() throws Exception {
        replayAllControls();
        aFileMover.move(fileMockController.fileMock());
        verifyAllControls();
    }

    private void verifyAllControls() {
        fileMockController.verify();
        aDirMockControl.verify();
    }

    private void replayAllControls() {
        aDirMockControl.replay();
        fileMockController.replay();
    }

    public void testShouldBeRollbackable() throws Exception {
        fileMockController.setUpShouldBeRollbackableExpection();

        replayAllControls();
        aFileMover.move(fileMockController.mock);
        aFileMover.rollback();
        verifyAllControls();
    }

    public void testShouldRollbackAllMovingActions() throws Exception {
        FileMockController anotherFile = new FileMockController(ANOTHER_FILE_NAME, A_DIR, ANOTHER_FILE_PATH);

        fileMockController.setUpShouldBeRollbackableExpection();
        anotherFile.setUpShouldBeRollbackableExpection();

        anotherFile.replay();
        replayAllControls();

        aFileMover.move(fileMockController.fileMock());
        aFileMover.move(anotherFile.fileMock());
        aFileMover.rollback();

        verifyAllControls();
        anotherFile.verify();
    }
}
